/* -----------------------------------------------------------------------------
 * PROJECT    : lwf_common
 * FILE       : DesEncryptor.java
 *
 * HISTORY:
 * Date          Author                        Description
 * ----------------------------------------------------------------------------- 
 * Nov 17, 2010  mycodetalks			       Created
 */
package net.lwf.security;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;

import net.lwf.common.constant.ICommonConstant;
import net.lwf.exception.ExceptionUtil;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * Class description goes here
 */
public class DesEncryptor {

	private KeySpec keySpec;
	private SecretKeyFactory keyFactory;
	private Cipher cipher;

	// private static final String UNICODE_FORMAT = "UTF8"; moved to constant as UTF-8

	public DesEncryptor()  {
		this(ICommonConstant.DESEDE_ENCRYPTION_SCHEME,
				ICommonConstant.DEFAULT_ENCRYPTION_KEY);
	}

	public DesEncryptor(String encryptionKey) {
		this(ICommonConstant.DESEDE_ENCRYPTION_SCHEME, encryptionKey);
	}

	public DesEncryptor(String encryptionScheme, String encryptionKey) {

		if (encryptionKey == null) {
			IllegalArgumentException iaex = new IllegalArgumentException("encryption key was null");
			ExceptionUtil.logAndThrowException(DesEncryptor.class, iaex);
		}
		if (encryptionKey.trim().length() < 24) {
			IllegalArgumentException iaex = new IllegalArgumentException("encryption key was less than 24 characters");
			ExceptionUtil.logAndThrowException(DesEncryptor.class, iaex);
		}
		try {
			byte[] keyAsBytes = encryptionKey
					.getBytes(ICommonConstant.CHARACTER_ENCODING);

			if (encryptionScheme
					.equals(ICommonConstant.DESEDE_ENCRYPTION_SCHEME)) {
				keySpec = new DESedeKeySpec(keyAsBytes);
			} else if (encryptionScheme
					.equals(ICommonConstant.DES_ENCRYPTION_SCHEME)) {
				keySpec = new DESKeySpec(keyAsBytes);
			} else {
				throw new IllegalArgumentException(
						"Encryption scheme not supported: " + encryptionScheme);
			}

			keyFactory = SecretKeyFactory.getInstance(encryptionScheme);
			cipher = Cipher.getInstance(encryptionScheme);
		} 
	
		catch (InvalidKeyException ikex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, ikex);
		}
		catch (IOException ioex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, ioex);
		}
		catch (NoSuchAlgorithmException nsaex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, nsaex);
		}
		catch (NoSuchPaddingException nspex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, nspex);
		}



	}

	public String encrypt(String unencryptedString)  {
		String encrypted = null;
		if (unencryptedString == null || unencryptedString.trim().length() == 0) {
			IllegalArgumentException iaex = new IllegalArgumentException("unencrypted string was null or empty");
			ExceptionUtil.logAndThrowException(DesEncryptor.class, iaex);
		}

		try {
			SecretKey key = keyFactory.generateSecret(keySpec);
			cipher.init(Cipher.ENCRYPT_MODE, key);
			byte[] cleartext = unencryptedString
					.getBytes(ICommonConstant.CHARACTER_ENCODING);
			byte[] ciphertext = cipher.doFinal(cleartext);

			BASE64Encoder base64encoder = new BASE64Encoder();
			encrypted = base64encoder.encode(ciphertext);
			encrypted = new StringBuilder(encrypted).reverse().toString();
		} 
		catch (InvalidKeySpecException iksex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, iksex);
		}
		catch (InvalidKeyException ikex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, ikex);
		}
		catch (IOException ioex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, ioex);
		}
		catch (BadPaddingException bpex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, bpex);
		}
		catch (IllegalBlockSizeException ibsex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, ibsex);
		}
			return encrypted;
	}

	public String decrypt(String encryptedString) {
		String decrypted = null;
		if (encryptedString == null || encryptedString.trim().length() <= 0) {
			IllegalArgumentException iaex = new IllegalArgumentException("encrypted string was null or empty");
			ExceptionUtil.logAndThrowException(DesEncryptor.class, iaex);
		}

		try {

			SecretKey key = keyFactory.generateSecret(keySpec);
			cipher.init(Cipher.DECRYPT_MODE, key);
			BASE64Decoder base64decoder = new BASE64Decoder();
			byte[] cleartext = base64decoder.decodeBuffer(new StringBuilder(
					encryptedString).reverse().toString());
			//byte[] cleartext = base64decoder.decodeBuffer(encryptedString);
			byte[] ciphertext = cipher.doFinal(cleartext);

			decrypted = bytes2String(ciphertext);
		} 
		catch (InvalidKeySpecException iksex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, iksex);
		}
		catch (InvalidKeyException ikex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, ikex);
		}
		catch (IOException ioex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, ioex);
		}
		catch (BadPaddingException bpex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, bpex);
		}
		catch (IllegalBlockSizeException ibsex) {
			ExceptionUtil.logAndThrowException(DesEncryptor.class, ibsex);
		}
		return decrypted;
	}

	private static String bytes2String(byte[] bytes) {
		StringBuffer stringBuffer = new StringBuffer();
		for (int i = 0; i < bytes.length; i++) {
			stringBuffer.append((char) bytes[i]);
		}
		return stringBuffer.toString();
	}

}



